home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Compilers⁄Interps / kevoSource / portEdit.c < prev    next >
Text File  |  1993-05-16  |  20KB  |  653 lines

  1. /* Kevo -- a prototype-based object-oriented language */
  2. /* (c) Antero Taivalsaari 1991-1993                   */
  3. /* Some parts (c) Antero Taivalsaari 1986-1988           */
  4. /* portEdit.c: The browser's object editing facilities */
  5.  
  6. #include "global.h"
  7. #include "portGlobal.h"
  8.  
  9. /*---------------------------------------------------------------------------*/
  10. /* Object scrap (ClipList) operations */
  11.  
  12. /* Given a cell, add the corresponding pair to the clip list */
  13. /* Since the CUT command causes the original PAIR to be disposed of */
  14. /* we make a copy of the pair before assigning it to the clip list */
  15.  
  16. void cellToClipList(browserWindow, cell)
  17. WindowPtr browserWindow;
  18. Cell       cell;
  19. {
  20.   PAIR* thisPair = cellToPair(browserWindow, cell);
  21.  
  22.     if (thisPair) addToList(ClipList, copyPair(thisPair));
  23. }
  24.  
  25.  
  26. /* Since the clip list contains copies of PAIRs rather than */
  27. /* references to the original pairs, the copies must be deleted */
  28. /* when the clip list is emptied */
  29.  
  30. void emptyClipList()
  31. {
  32.   int index;
  33.  
  34.     for (index = 1; index <= ClipList->logicalSize; index++) 
  35.         free((PAIR*)fetchFromList(ClipList, index));
  36.     ClipObject = NIL;
  37.     
  38.     emptyList(ClipList);
  39. }
  40.  
  41.  
  42. /*---------------------------------------------------------------------------*/
  43. /* Graphical user interface editing operations */
  44.  
  45. /* Do a 'CUT' operation */
  46. /* Remember: this operation can create garbage which is never collected */
  47. /*           (xxx implement garbage collector later) */
  48.  
  49. void doCut()
  50. {
  51.   WindowPtr thisWindow = FrontWindow();
  52.   int wKind = getWindowKind(thisWindow);
  53.  
  54.     switch (wKind) {
  55.         case PlainWKind:
  56.         case TEWKind:
  57.             if (theText) TECut(theText);
  58.             break;
  59.             
  60.         case BrowserWKind: {
  61.             OBJECT* cwd = getBrowserTarget(thisWindow);
  62.             PAIR* firstRemovedPairSucc = NIL;
  63.             ListHandle iconList = getBrowserIcons(thisWindow);
  64.             Cell cell;
  65.             Cell firstSelectedCell;
  66.  
  67.             if (whoToModify == DERIVATIVES) {
  68.                 SysBeep(1);
  69.                 fprintf(confile, "== This version does not support CUT in the 'derivatives' mode ==\n");  
  70.                 break;
  71.             }
  72.     
  73.               /* Get the first selected pair (needed later) */
  74.             /* If nothing is selected, return */
  75.             firstSelectedCell.h = -1; firstSelectedCell.v = 0;
  76.             if (!nextSelectedCell(iconList, &firstSelectedCell)) break;
  77.  
  78.               /* Create new clone family if needed */
  79.               if (whoToModify == THIS_ONLY) deriveObject(cwd);
  80.   
  81.             /* Initialize object clipboard information */
  82.                 emptyClipList();
  83.                 ClipObject = cwd;
  84.                 ClipMode = CLIP_CUT;
  85.                 deleteContext(ClipContext);
  86.                 ClipContext = copyContext(getContext(cwd));
  87.  
  88.             /* Copy the selected pairs to the clip list (in the backward order) */
  89.             /* and delete the pairs from the object */
  90.             cell.h = (*iconList)->dataBounds.right; 
  91.             cell.v = (*iconList)->dataBounds.bottom-1;
  92.             if (prevSelectedCell(iconList, &cell)) {
  93.               PAIR* tempPair;
  94.               
  95.                 cellToClipList(thisWindow, cell);
  96.                 LSetSelect(FALSE, cell, iconList);
  97.                 
  98.                 /* Ensure that we are not trying to cut array slots */
  99.                 tempPair = cellToPair(thisWindow, cell);
  100.                 if (!tempPair) goto finalize;
  101.                 
  102.                 /* Store the successor of the first pair to be cut */
  103.                 firstRemovedPairSucc = tempPair->sfa;
  104.                 removeCell(thisWindow, cell);
  105.  
  106.                 while (prevSelectedCell(iconList, &cell)) {
  107.                     cellToClipList(thisWindow, cell);
  108.                     LSetSelect(FALSE, cell, iconList);
  109.                     
  110.                     /* Since we are removing properties in the backwards order,
  111.                        we must update the successor information (we are trying
  112.                        to find the successor of the FIRST pair to be removed).
  113.                     */
  114.                     /* Ensure that we are not cutting array slots */
  115.                     tempPair = cellToPair(thisWindow, cell);
  116.                     if (!tempPair) goto finalize;
  117.                     
  118.                     firstRemovedPairSucc = tempPair->sfa;
  119.                     removeCell(thisWindow, cell);
  120.                 }
  121.  
  122.             finalize:
  123.                 /* Possibly change the object's clone family */
  124.                 confirmObjectType(cwd, whoToModify, REMOVING_SOMETHING);
  125.             
  126.                 /* Rebind the early bound references within the changed object */
  127.                 /* starting from the successor of the first non-removed pair */
  128.                 if (firstRemovedPairSucc) rebindContext(firstRemovedPairSucc, ClipContext);
  129.             
  130.                 updateBrowser(thisWindow);
  131.             }
  132.             break;
  133.         }
  134.         case CloneBrWKind:
  135.             /* Editing of clone families is not allowed */
  136.             break;
  137.     }
  138. }
  139.  
  140.  
  141. /* Do a 'COPY' operation */
  142.  
  143. void doCopy()
  144. {
  145.   WindowPtr thisWindow = FrontWindow();
  146.   int wKind = getWindowKind(thisWindow);
  147.  
  148.     switch (wKind) {
  149.         case PlainWKind:
  150.         case TEWKind:
  151.             if (theText) TECopy(theText);
  152.             break;
  153.             
  154.         case BrowserWKind: {
  155.             ListHandle iconList = getBrowserIcons(thisWindow);
  156.             OBJECT* cwd = getBrowserTarget(thisWindow);
  157.             Cell cell;
  158.  
  159.             /* Copy the selected pairs to the clip list */
  160.             cell.h = (*iconList)->dataBounds.right; 
  161.             cell.v = (*iconList)->dataBounds.bottom-1;
  162.             if (prevSelectedCell(iconList, &cell)) {
  163.  
  164.                 /* Initialize object clipboard information */
  165.                 emptyClipList();
  166.                 ClipObject = cwd;
  167.                 ClipMode = CLIP_COPY;
  168.                 deleteContext(ClipContext);
  169.                 ClipContext = copyContext(getContext(cwd));
  170.  
  171.                 cellToClipList(thisWindow, cell);
  172.  
  173.                 while (prevSelectedCell(iconList, &cell)) {
  174.                     cellToClipList(thisWindow, cell);
  175.                 }
  176.             }
  177.  
  178.             /*
  179.                 Idea: copy the name of the latest selected cell 
  180.                 to the TE scrap buffer. Implement later? xxx
  181.                 Suggested code moved to 'oldCode.c'.
  182.             */
  183.             break;
  184.         }
  185.         case CloneBrWKind:
  186.             /* Editing of clone families is not allowed */
  187.             break;
  188.     }
  189. }
  190.  
  191.  
  192. /* Do a 'PASTE' operation */
  193.  
  194. void doPaste()
  195. {
  196.   WindowPtr thisWindow = FrontWindow();
  197.   int wKind = getWindowKind(thisWindow);
  198.  
  199.     switch (wKind) {
  200.         case PlainWKind:
  201.         case TEWKind:
  202.             if (theText) TEPaste(theText); 
  203.             if (theTask) {    
  204.                 /* If the window has an associated task */
  205.                 /* put the pasted text into its text buffer */
  206.                 char c;
  207.                 char*    clipBuf = (char*)*TEScrapHandle();
  208.                 int        clipLen = TEGetScrapLen();
  209.                 while (clipLen--) {
  210.                     putToKeyBuffer(theTask, c = *clipBuf++);
  211.                     if (c == CR || c == LF) putToKeyBuffer(theTask, c);
  212.                 }
  213.                 /* Lines must be separated by two returns or linefeeds */
  214.                 crsToKeyBuffer(theTask);
  215.             }
  216.             break;
  217.             
  218.         case BrowserWKind: {
  219.             OBJECT* cwd = getBrowserTarget(thisWindow);
  220.             PAIR* thisPair = NIL;
  221.             PAIR* firstPastedPair = NIL;
  222.             ListHandle iconList = getBrowserIcons(thisWindow);
  223.             int selected = countSelectedCells(iconList);
  224.             int index;
  225.  
  226.             /* If the object clipboard is empty, don't do anything */
  227.             if (ClipList->logicalSize == 0) break;
  228.  
  229.             if (whoToModify == DERIVATIVES) {
  230.                 SysBeep(1);
  231.                 fprintf(confile, "== This version does not support PASTE in the 'derivatives' mode ==\n");  
  232.                 break;
  233.             }
  234.     
  235.             /* If the number of selected cells is > 1, cannot paste */
  236.             if (selected > 1) {
  237.                 SysBeep(1);
  238.                 fprintf(confile, "== Cannot paste to a browser with more than one selected cell ==\n");
  239.                 break;
  240.             }
  241.  
  242.               /* Create new clone family if needed */
  243.               if (whoToModify == THIS_ONLY) deriveObject(cwd);
  244.   
  245.             /* If the number of selected cells is 1, add before the selected cell */
  246.             if (selected) {
  247.               Cell cell;
  248.  
  249.                 cell.h = -1; cell.v = 0;
  250.                 (void)nextSelectedCell(iconList, &cell);
  251.  
  252.                 /* Ensure that the selected cell is not an anonymous indexed slot */
  253.                 thisPair = cellToPair(thisWindow, cell);
  254.                 if (thisPair) {
  255.                     PAIR* oldPair;
  256.                     PAIR* newPair;
  257.  
  258.                     /* Walk through the object clip list containing the pairs to be pasted */
  259.                     /* Adding the properties before the requested pair */
  260.                     /* Recall that pairs are stored in the clip list backwards */
  261.  
  262.                     oldPair = (PAIR*)fetchFromList(ClipList, ClipList->logicalSize);
  263.                     newPair = addBeforePair(thisPair, copyPair(oldPair));
  264.                     firstPastedPair = newPair;                    
  265.  
  266.                     for (index = ClipList->logicalSize - 1; index >= 1; index--) {
  267.                         PAIR* oldPair = (PAIR*)fetchFromList(ClipList, index);
  268.                         PAIR* newPair;
  269.  
  270.                         /* Add the slot to the correct place in the object */
  271.                         newPair = addBeforePair(thisPair, copyPair(oldPair));
  272.  
  273.                         /* Local ("instance") variables require special attention */
  274.                         /* However, no new space for instance variables is needed */
  275.                         /* if we are cutting and pasting inside the same object */
  276.                         if (recognizeObject(newPair->ofa) == VAR &&
  277.                             !(ClipObject == cwd && ClipMode == CLIP_CUT)) 
  278.                             pasteInstanceVariable(ClipObject, cwd, oldPair, newPair);
  279.                     }
  280.                 }
  281.             }
  282.             /* If the number of selected cells is 0, add to the end of the object */
  283.             else {
  284.                   OBJECT*  cwd      = getBrowserTarget(thisWindow);
  285.                   CONTEXT* context = getContext(cwd); 
  286.  
  287.                 firstPastedPair = context->latestPair;
  288.  
  289.                 /* Walk through the object clip list containing the pairs to be pasted */
  290.                 for (index = ClipList->logicalSize; index >= 1; index--) {
  291.                     PAIR* oldPair = (PAIR*)fetchFromList(ClipList, index);
  292.                     PAIR* newPair;
  293.  
  294.                     /* 
  295.                         Add a new pair to the end of the context using the
  296.                         information from the old pair. Since 'addPair' initializes
  297.                         the flags (ffa), we must copy that field manually.
  298.                     */
  299.                      newPair = addPair(context, oldPair->nfa, oldPair->ofa);            
  300.                     newPair->ffa = oldPair->ffa;
  301.  
  302.                     /* Local ("instance") variables require special attention */
  303.                     /* However, no new space for instance variables is needed */
  304.                     /* if we are cutting and pasting inside the same object */
  305.                     if (recognizeObject(oldPair->ofa) == VAR &&
  306.                         !(ClipObject == cwd && ClipMode == CLIP_CUT)) 
  307.                         pasteInstanceVariable(ClipObject, cwd, oldPair, newPair);
  308.                 }
  309.                 if (firstPastedPair)
  310.                      firstPastedPair = firstPastedPair->sfa;
  311.                 else firstPastedPair = context->firstPair;
  312.             }
  313.  
  314.             /* If the properties have been COPIED (rather than CUT) */
  315.             /* We make the donor object a parent of the current (recipient) object */
  316.             if (ClipMode == CLIP_COPY && cwd != ClipObject) {
  317.                 makeParent(cwd, ClipObject);
  318.             }
  319.  
  320.             /* Possibly change the object's clone family */
  321.             confirmObjectType(cwd, whoToModify, PASTING_SOMETHING);
  322.             
  323.             /* Rebind the early bound references within the changed object */
  324.             /* starting from the first added pair */
  325.             if (firstPastedPair) rebindContext(firstPastedPair, ClipContext);
  326.             
  327.             updateBrowser(thisWindow);
  328.             break;
  329.         }
  330.         case CloneBrWKind:
  331.             /* Editing of clone families is not allowed */
  332.             break;
  333.     }
  334. }
  335.  
  336.  
  337. /* Do a 'REMOVE' operation */
  338. /* Remember: this operation can create garbage which is never collected */
  339. /*           (xxx implement garbage collector later) */
  340.  
  341. void doRemove()
  342. {
  343.   WindowPtr thisWindow = FrontWindow();
  344.   int wKind = getWindowKind(thisWindow);
  345.  
  346.     switch (wKind) {
  347.         case PlainWKind:
  348.         case TEWKind:
  349.             if (theText) TEDelete(theText);
  350.             break;
  351.             
  352.         case BrowserWKind: {
  353.             OBJECT* cwd = getBrowserTarget(thisWindow);
  354.             PAIR* firstRemovedPairSucc = NIL;
  355.             ListHandle iconList = getBrowserIcons(thisWindow);
  356.             Cell cell;
  357.             Cell firstSelectedCell;
  358.             
  359.             if (whoToModify == DERIVATIVES) {
  360.                 SysBeep(1);
  361.                 fprintf(confile, "== This version does not support REMOVE in the 'derivatives' mode ==\n");  
  362.                 break;
  363.             }
  364.     
  365.               /* Get the first selected cell (needed later) */
  366.             /* If nothing is selected, return */
  367.             firstSelectedCell.h = -1; firstSelectedCell.v = 0;
  368.             if (!nextSelectedCell(iconList, &firstSelectedCell)) break;
  369.  
  370.             /* Create a new clone family if needed */
  371.             if (whoToModify == THIS_ONLY) deriveObject(cwd);
  372.  
  373.             /* Remove the selected cells from the object */
  374.             cell.h = (*iconList)->dataBounds.right; 
  375.             cell.v = (*iconList)->dataBounds.bottom-1;
  376.             if (prevSelectedCell(iconList, &cell)) {
  377.               PAIR* tempPair;
  378.  
  379.                 CONTEXT* oldContext = copyContext(getContext(cwd));
  380.                 LSetSelect(FALSE, cell, iconList);
  381.  
  382.                 /* Ensure that we are not trying to remove array slots */
  383.                 tempPair = cellToPair(thisWindow, cell);
  384.                 if (!tempPair) goto finalize;
  385.  
  386.                 /* Store the successor of the first pair to be removed */
  387.                 firstRemovedPairSucc = tempPair->sfa;
  388.                 removeCell(thisWindow, cell);
  389.  
  390.                 while (prevSelectedCell(iconList, &cell)) {
  391.                     LSetSelect(FALSE, cell, iconList);
  392.                     
  393.                     /* Since we are removing properties in the backwards order,
  394.                        we must update the successor information (we are trying
  395.                        to find the successor of the FIRST pair to be removed).
  396.                     */
  397.                     /* Ensure we are not trying to remove array slots */
  398.                     tempPair = cellToPair(thisWindow, cell);
  399.                     if (!tempPair) goto finalize;
  400.                     
  401.                     firstRemovedPairSucc = tempPair->sfa;
  402.                     removeCell(thisWindow, cell);
  403.                 }
  404.  
  405.             finalize:
  406.                 /* Possibly change the object's clone family */
  407.                 confirmObjectType(cwd, whoToModify, REMOVING_SOMETHING);
  408.  
  409.                 /* Rebind the early bound references within the changed object */
  410.                 /* starting from the successor of the first removed pair */
  411.                 if (firstRemovedPairSucc) rebindContext(firstRemovedPairSucc, oldContext);
  412.             
  413.                 updateBrowser(thisWindow);
  414.                 deleteContext(oldContext);
  415.             }
  416.             else {
  417.                 SysBeep(1);
  418.                 fprintf(confile, "== Nothing to REMOVE ==\n");
  419.             }
  420.             break;
  421.         }
  422.         case CloneBrWKind:
  423.             /* Editing of clone families is not allowed */
  424.             break;
  425.     }
  426. }
  427.  
  428.  
  429. /* Do a 'SELECT ALL' operation */
  430.  
  431. void doSelectAll()
  432. {
  433.   int wKind = getWindowKind(FrontWindow());
  434.  
  435.     switch (wKind) {
  436.         case PlainWKind:
  437.         case TEWKind:
  438.             if (theText) TESetSelect(0, 32767, theText);
  439.             break;
  440.             
  441.         case BrowserWKind: {
  442.             ListHandle iconList = getBrowserIcons(FrontWindow()); 
  443.             Cell cell;
  444.             cell.h = 0; cell.v = 0;
  445.             do {
  446.                 LSetSelect(TRUE, cell, iconList);
  447.             } while (LNextCell(TRUE, TRUE, &cell, iconList));
  448.             break;
  449.         }
  450.         case CloneBrWKind:
  451.             /* Editing of clone families is not allowed */
  452.             break;
  453.     }
  454. }
  455.  
  456.  
  457. /* Do a 'SHOW/HIDE' operation */
  458.  
  459. void doShowHide() 
  460. {
  461.   WindowPtr browserWindow = FrontWindow();
  462.   OBJECT* cwd = getBrowserTarget(browserWindow);
  463.   ListHandle iconList = getBrowserIcons(browserWindow);
  464.   Cell cell;
  465.  
  466.     if (whoToModify == DERIVATIVES) {
  467.         SysBeep(1);
  468.         fprintf(confile, "== This version does not support HIDE/SHOW in the 'derivatives' mode ==\n");  
  469.         return;
  470.     }
  471.     
  472.     cell.h = -1; cell.v = 0;
  473.     if (nextSelectedCell(iconList, &cell)) {
  474.  
  475.         /* Create a new clone family if needed */
  476.         if (whoToModify == THIS_ONLY) deriveObject(cwd);
  477.  
  478.         hideShowCell(browserWindow, cell);
  479.  
  480.         while (nextSelectedCell(iconList, &cell)) {
  481.             hideShowCell(browserWindow, cell);
  482.         }
  483.  
  484.         /* Possibly change the object's clone family */                        
  485.         confirmObjectType(cwd, whoToModify, ENCAPSULATING_SOMETHING);
  486.         updateBrowser(browserWindow);
  487.     }
  488.     else {
  489.         SysBeep(1);
  490.         fprintf(confile, "== No cells selected ==\n");
  491.     }
  492. }
  493.  
  494.  
  495. /* Redefine a method if the user has changed the decompiled definition */
  496. /* in the method display window (which is a TextEdit window) */
  497. /* The WINFO structure contains additional information about the */
  498. /* method to be redefined */
  499.  
  500. void redefineMethod(methodWindow)
  501. WindowPtr methodWindow;
  502. {
  503.   OBJECT*     cwd = getMethodContext(methodWindow);
  504.   PAIR*     pair = getMethodPair(methodWindow);
  505.   
  506.   TEHandle thisTE     = getWindowTE(methodWindow);
  507.   char** textHandle = (char**)TEGetText(thisTE);
  508.   short textLen     = (*thisTE)->teLength;
  509.   
  510.     if (browserTask && textLen && strncmp(*textHandle, ":: ", 3)) {
  511.           /* If the beginning of the string has been changed -> redefine */
  512.         char* textPtr = *textHandle;
  513.         
  514.         /* Recompilation must take place in the original context. */
  515.         /* Since other tasks might be running the currently redefined */
  516.         /* operation, we use a critical region to avoid interference */
  517.         numberToKeyBuffer(browserTask, (int)cwd);
  518.         textToKeyBuffer(browserTask, " CD <|");
  519.         crsToKeyBuffer(browserTask);
  520.  
  521.         /* Use the special 'bredef' operation to handle recompilation */
  522.         /* Parameters: ( whoToModify pair --  ) */
  523.         numberToKeyBuffer(browserTask, (int)pair);
  524.         putToKeyBuffer(browserTask, BL);
  525.         numberToKeyBuffer(browserTask, whoToModify);
  526.         textToKeyBuffer(browserTask, " bredef");
  527.         crsToKeyBuffer(browserTask);
  528.  
  529.         /* Put the contents of the window's TE to */
  530.         /* the input buffer of the browser task */
  531.         while (textLen--) {
  532.             char c = *textPtr++;
  533.             putToKeyBuffer(browserTask, c);
  534.              if (c == CR) {
  535.                  putToKeyBuffer(browserTask, c);
  536.                  if (*textPtr == CR) break;    /* Two CR's (empty line) -> ignore rest */
  537.              }
  538.          }
  539.  
  540.         textToKeyBuffer(browserTask, " NOW |>");
  541.         crsToKeyBuffer(browserTask);
  542.       }
  543. }
  544.   
  545.  
  546. /* This is an internal operation which is needed only in the next operation */
  547. /* It clones an existing object (if it is an object) on background using */
  548. /* 'browserTask', and assigns it to a given location */
  549.  
  550. void cloneOnBackground(oldValue, newSlot)
  551. OBJECT*  oldValue;
  552. OBJECT** newSlot;
  553. {
  554.      /* Copy the value to the given location */
  555.      *newSlot = oldValue;
  556.     
  557.     /* If the value is an object, clone it on background */        
  558.     if (isContextObject(oldValue) && respondsTo(oldValue, "copy")) {
  559.         /* Generated source code: oldValue.clone newSlot ! */
  560.         numberToKeyBuffer(browserTask, oldValue);
  561.         textToKeyBuffer(browserTask, ".clone ");
  562.         numberToKeyBuffer(browserTask, newSlot);
  563.         textToKeyBuffer(browserTask, " !");
  564.         crsToKeyBuffer(browserTask);
  565.     }
  566. }
  567.  
  568.  
  569. /* pasteInstanceVariable(): this operation takes care of necessary things
  570.    when local ("instance") variables are pasted to an object.
  571.  
  572.    The things to be done are:
  573.            - allocate space for an extra slot in the recipient
  574.              (actually, in every member of a clone family).
  575.            - if the offset of the slot differs from the original offset
  576.              recompile the code (and set the context to be recompiled).
  577.            - copy the value of the original slot to the new one.
  578.            - if the copied value in the slot is an OOP object, then
  579.              set 'browserTask' to clone the object in the background
  580.              (since local variables are local -- not shared).
  581. */
  582. void pasteInstanceVariable(oldObject, newObject, oldPair, newPair)
  583. OBJECT* oldObject;
  584. OBJECT* newObject;
  585. PAIR* oldPair;
  586. PAIR* newPair;
  587. {
  588.   CONTEXT* newContext = getContext(newObject);
  589.   LIST*    cloneFamily = newContext->cloneFamily;
  590.   int       familySize = cloneFamily->logicalSize;
  591.  
  592.   /* The offset of the instance variable in the old object */
  593.   int oldOffset = getVARoffset(oldPair);
  594.  
  595.   /* The offset of the instance variable in the new object */
  596.   int newOffset = newObject->sfa;
  597.  
  598.   /* The data value of the instance variable in the old object */
  599.   OBJECT* oldValue = *getVARslot(oldObject, oldPair);
  600.  
  601.     /* Allocate space for an extra slot in every instance of this object */
  602.     /* (in the THIS_ONLY mode, there is only one copy because of '<derive>') */
  603.     /* (so we don't have to worry about resizing extra objects) */
  604.     resizeFamilyMembers(newObject, newObject->sfa + 1);
  605.     
  606.     /* If offsets do not match, we have to redefine the operation */
  607.     /* in the new object. In order to ensure that everything is ok */
  608.     /* after doing this, you must call 'rebindContext' immediately */
  609.     /* after returning from 'pasteInstanceVariable'. */ 
  610.     
  611.     if (oldOffset != newOffset) {
  612.         /* Copy the operation */
  613.         /* The operation is a method like this: "(=VAR) offset" */
  614.         newPair->ofa = copyObject(oldPair->ofa);
  615.         
  616.         /* When changing the offset, we utilize the fact that 
  617.            the offset is stored like a shared variable. 
  618.         */
  619.         *getREFslot(newPair) = (OBJECT*)newOffset;
  620.     }
  621.  
  622.     /* 
  623.         Copy the value in the old object's variable slot to the new 
  624.         data slot in every member in the clone family.
  625.         
  626.         Furthermore, if the original value is an object id,
  627.         set 'browserTask' to clone it on the background.
  628.     */
  629.  
  630.     if (familySize > 0) {
  631.           int index;
  632.     
  633.         /* Walk through each object in the new object's clone family */
  634.         for (index = 1; index <= familySize; index++) {
  635.             OBJECT*  member = (OBJECT*)fetchFromList(cloneFamily, index);
  636.             OBJECT** newSlot = getVARslot(member, newPair);
  637.  
  638.             cloneOnBackground(oldValue, newSlot);
  639.         }            
  640.     }
  641.     /* 
  642.         In the current implementation, it is possible that some objects 
  643.         have an empty clone family. For such objects, do the same as above
  644.         individually (without going through the clone family).
  645.     */
  646.     else {
  647.         OBJECT** newSlot = getVARslot(newObject, newPair);
  648.         cloneOnBackground(oldValue, newSlot);
  649.     }
  650. }
  651.  
  652.  
  653.